using UnityEngine;
using System.Collections;

public class PlayerControl : CharacterControl<PlayerControl>, IReceiver 
{
    #region Attributes

    /* Sounds */
    public AudioClip bounceSound;
    public AudioClip rollSound;

    [HideInInspector]
    public Transform playerPrefab;

    /* Movement Control */
    [HideInInspector]
    public Vector3 targetPosition;
    [HideInInspector]
    public float offset = 0.1f;
    [HideInInspector]
    public Vector3 initialPosition;
    [HideInInspector]
    public Vector3 directionToMove = new Vector3(0, 0, 0);
    public float dirChangeSpeed = 0.1f;
    [HideInInspector]
    public bool isMoving = false;

    /* Death Control */ 
    private DeathCounterControl deathCounterControl = null;
	private MenuControl menu = null;
    [HideInInspector]
    public int enemiesInAlert = 0;
    [HideInInspector]
    public bool die = false;

    /* Switch Control */
    [HideInInspector]
    public bool doActionOnTargetPosition = false;
    [HideInInspector]
    public SwitchControl switchControl = null;
    public float offsetFromSwitch = 0.5f;
    private bool isNearSwitch = false;
    private GameObject switchToActivate = null;
	
    /* Sound Wave */
    public GameObject soundWave = null;	

    #endregion

    #region Methods

    public void EnemyAlertEnter()
    {
        ++this.enemiesInAlert;
    }

    public void EnemyAlertExit()
    {
        --this.enemiesInAlert;
    }   

    public void Die()
    {
        this.playerPrefab.animation.Play(AnimationConstants.PLAYER_DEATH);
        this.die = true;
        this.menu.dead = true;
    }

    public void ChangeEnergy(float quantity, bool permanent)
    {
        this.deathCounterControl.ChangeEnergy(quantity, permanent);
    }

/*    public void CreateSoundWave()
    {
        // Provisorio para hoy
        Vector3 soundPosition = this.playerPrefab.transform.position;
        soundPosition.y = 0; // Poner valor correcto de Y
        Instantiate(this.soundWave, soundPosition, Quaternion.Euler(90, 0, 0));
        Debug.Log("Parent");
    }
*/
    public bool PlayerCanMove()
    {
        bool result = true;

        RaycastHit hit;
        if (Physics.Raycast(this.transform.position, this.transform.forward, out hit, this.checkCanMoveDistance) &&
            hit.collider.tag == TagConstants.TAG_DOOR)
        {
            DoorControl control = hit.collider.gameObject.GetComponent<DoorControl>();
            if (control.State == DoorCloseState.Instance)
                result = false;
        }

        return result;
    }

    #endregion

    #region Unity Methods

    void Start () 
    {
        this.isMoving = false;

        this.playerPrefab = transform.FindChild(TextConstants.PLAYER_NAME);

        AnimationEvent evt = new AnimationEvent();
        evt.time = 0;
        evt.objectReferenceParameter = this.soundWave;

        // Llamara a la funcion en el child (prefab). Hay que hacerlo asi porque la funcion tiene que estar en el mismo GameObject que la animacion
        evt.functionName = "CreateSoundWaves";
        this.playerPrefab.animation[AnimationConstants.PLAYER_JUMP_LOOP].clip.AddEvent(evt);

        this.deathCounterControl = GameObject.FindGameObjectWithTag(TagConstants.TAG_CAMERA).GetComponentInChildren<DeathCounterControl>();
        this.menu = GameControl.FindMenu();
		this.initialPosition = this.gameObject.transform.position;
        this.Init(PlayerRespawnState.Instance);
        this.updateCalledIn = StateBehaviourMethodsName.Update;
    }

    void OnTriggerEnter(Collider other)
    {
        if (other.tag == TagConstants.TAG_SWITCH)
        {
            this.isNearSwitch = true;
            this.switchToActivate = other.gameObject;
        }
		
		if (other.tag == TagConstants.TAG_RELOAD_BASE && this.enemiesInAlert <= 0)
        {
            this.deathCounterControl.State = DeathCounterFill.Instance;
            other.transform.FindChild(TextConstants.RELOAD_BASE_PARTICLES_NAME).GetComponentInChildren<ParticleEmitter>().emit = true;
        }

        if (other.tag == TagConstants.TAG_FINISH)
        {
            GameControl.NextLevel();
        }
    }

    void OnTriggerStay(Collider other)
    {
        if (other.tag == TagConstants.TAG_RELOAD_BASE && this.enemiesInAlert > 0)
        {
            this.deathCounterControl.State = DeathCounterEmpty.Instance;
            other.transform.FindChild(TextConstants.RELOAD_BASE_PARTICLES_NAME).GetComponentInChildren<ParticleEmitter>().emit = false;
        }
    }

    void OnTriggerExit(Collider other)
    {
        if (other.tag == TagConstants.TAG_SWITCH)
        {
            this.isNearSwitch = false;
            this.switchToActivate = null;
        }
		
		if (other.tag == TagConstants.TAG_RELOAD_BASE)
        {
            this.deathCounterControl.State = DeathCounterEmpty.Instance;
            other.transform.FindChild(TextConstants.RELOAD_BASE_PARTICLES_NAME).GetComponentInChildren<ParticleEmitter>().emit = false;
        }
    }

    #endregion

    #region StateBehaviour

    public override void OnUpdate()
    {
        /* Input por teclado */
        if (GameControl.isInputEnabled)
        {
            if (Input.GetKey(InputConstants.KEY_UP))
                this.directionToMove.z = 1;
            else if (Input.GetKey(InputConstants.KEY_DOWN))
                this.directionToMove.z = -1;
            else
                this.directionToMove.z = 0;

            if (Input.GetKey(InputConstants.KEY_RIGHT))
                this.directionToMove.x = 1;
            else if (Input.GetKey(InputConstants.KEY_LEFT))
                this.directionToMove.x = -1;
            else
                this.directionToMove.x = 0;

            if (this.directionToMove != Vector3.zero)
            {
                this.isMoving = true;

                if (Input.GetKey(InputConstants.KEY_RUN) || Input.GetKey(InputConstants.KEY_RUN_2))
                    this.State = PlayerRunState.Instance;
                else
                    this.State = PlayerWalkState.Instance;

                // Rotacion para encarar la direccion de movimiento
                Vector3 lookAt = this.directionToMove;
                this.transform.rotation = Quaternion.Slerp(this.transform.rotation,
                                                Quaternion.LookRotation(lookAt),
                                                this.dirChangeSpeed);
                this.Controller.updateRotation = true;
            }
            else
            {
                this.State = PlayerIdleState.Instance;
            }

            /* Activacion de interruptores */
            if (this.isNearSwitch && Input.GetKeyDown(InputConstants.KEY_ACTIVATE))
            {
                this.switchControl = this.switchToActivate.GetComponent<SwitchControl>();

                // Asignamos una posicion fija respecto al interruptor
                this.targetPosition.x = this.switchToActivate.transform.position.x
                                        + this.switchToActivate.transform.forward.x * this.offsetFromSwitch;
                this.targetPosition.y = this.transform.position.y;
                this.targetPosition.z = this.switchToActivate.transform.position.z
                                        + this.switchToActivate.transform.forward.z * this.offsetFromSwitch;
                this.doActionOnTargetPosition = true;
                GameControl.isInputEnabled = false;
                this.State = PlayerIdleState.Instance;
            }
        }
        
        if(!PlayerCanMove())
        {
            this.directionToMove = Vector3.zero;
            this.State = PlayerIdleState.Instance;
        }

        if (this.doActionOnTargetPosition)
        {
            if (this.MoveTo(this.targetPosition, this.activateSpeed))
                this.State = PlayerActivateSwitchState.Instance;
        }

        if (this.die)
        {
            if (!this.playerPrefab.animation.IsPlaying(AnimationConstants.PLAYER_DEATH))
            {
                this.State = PlayerRespawnState.Instance;
                this.die = false;
            }
        }
    }

    public override PlayerControl GetBehaviuor()
    {
        return this;
    }

    #endregion

    #region IReceiver

    public void Action(params object[] args)
    {
        Debug.Log("INTERRUPTOR PULSADO, vuelvo a IDLE");
        this.Controller.ResetPath();
        this.State = PlayerIdleState.Instance;
    }

    #endregion
}
